package com.mchat.communication.service.impl;

import com.mchat.common.dto.bo.OnlineUser;
import com.mchat.communication.exception.NotFoundException;
import com.mchat.communication.protocol.IMEncoder;
import com.mchat.communication.protocol.IMMessage;
import com.mchat.communication.service.OnlineUserService;
import com.mchat.communication.service.UserService;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class OnlineUserServiceImpl implements OnlineUserService {
    @Resource
    private IMEncoder encoder;
    @Resource
    private UserService userService;
    public static final AttributeKey<String> USERNAME = AttributeKey.valueOf("userName");
    public static final AttributeKey<String> AVATAR = AttributeKey.valueOf("avatar");
    public static final AttributeKey<String> IP_ADDR = AttributeKey.valueOf("ipAddress");
    public static final AttributeKey<String> USER_SEQ = AttributeKey.valueOf("userSeq");

    private static final Map<String, OnlineUser> ONLINE_USERS = new ConcurrentHashMap<>();

    @Override
    public OnlineUser getUserByName(String userName) {
        String userSeq = userService.getUserSeqByUserName(userName);
        return getUserBySeq(userSeq);
    }

    @Override
    public OnlineUser getUserBySeq(String userSeq) {
        return ONLINE_USERS.get(userSeq);
    }

    @Override
    public OnlineUser getUserById(Integer userId) throws NotFoundException {
        String userSeq = userService.getUserSeqByUserId(userId);
        return getUserBySeq(userSeq);
    }

    @Override
    public boolean removeUserByName(String userName) {
        String userSeq = userService.getUserSeqByUserName(userName);
        return removeUserBySeq(userSeq);
    }

    @Override
    public boolean removeUserBySeq(String userSeq) {
        ONLINE_USERS.remove(userSeq);
        return true;
    }

    @Override
    @SneakyThrows
    public boolean removeUserById(Integer userId) {
        String userSeq = userService.getUserSeqByUserId(userId);
        return removeUserBySeq(userSeq);
    }

    @Override
    public boolean removeUser(OnlineUser user) {
        return removeUserBySeq(user.getUserSeq());
    }

    @Override
    public OnlineUser addOnlineUser(OnlineUser user) {
        Channel client = user.getClient();
        client.attr(IP_ADDR).getAndSet(user.getIpAddress());
        client.attr(USERNAME).getAndSet(user.getUserName());
        client.attr(AVATAR).getAndSet(user.getAvatar());
        client.attr(USER_SEQ).getAndSet(user.getAvatar());
        return ONLINE_USERS.put(user.getUserSeq(), user);
    }

    @Override
    public OnlineUser modifyUser(OnlineUser onlineUser) {
        return ONLINE_USERS.put(onlineUser.getUserSeq(), onlineUser);
    }

    @Override
    public IMMessage sendMessage(OnlineUser user, IMMessage message) {
        if ("ALL".equals(message.getReceiver())) {
            sendMessageToAll(user, message);
        } else {
            sendMessageToReceiver(message);
        }
        return message;
    }

    @Override
    public Integer countOnlineUsers() {
        return ONLINE_USERS.size();
    }

    private void sendMessageToReceiver(IMMessage message) {
        OnlineUser receiver = getUserByName(message.getReceiver());
        String text = encoder.encode(message);
        receiver.getClient().writeAndFlush(new TextWebSocketFrame(text));
    }

    private void sendMessageToAll(OnlineUser user, IMMessage message) {
        for (Map.Entry<String, OnlineUser> keySet : ONLINE_USERS.entrySet()) {
            OnlineUser onlineUser = keySet.getValue();
            //自定义IM协议解码
            String text = encoder.encode(message);
            //发送消息
            onlineUser.getClient().writeAndFlush(new TextWebSocketFrame(text));
        }
    }
}
